﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using DiscoveryLogic.Analytics.DataObjects.Visuals;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.DataObjects
{
    public class Vertice
    {
        #region events
        /// <summary>
        /// 
        /// </summary>
        /// <param name="v"></param>
        public delegate void VerticeMovedEventHandler(Vertice v);

        public event VerticeMovedEventHandler Move;
        #endregion

        #region general
        private Guid _ID;
        /// <summary></summary>
        public Guid ID
        {
            get
            {
                return this._ID;
            }
            set
            {
                this._ID = value;
            }
        }

        //private int _Group;
        ///// <summary></summary>
        //public int Group
        //{
        //    get
        //    {
        //        return this._Group;
        //    }
        //    set
        //    {
        //        this._Group = value;
        //    }
        //}

        //private TextBlock _Label;
        ///// <summary></summary>
        //public TextBlock Label
        //{
        //    get
        //    {
        //        return this._Label;
        //    }
        //    set
        //    {
        //        this._Label = value;
        //    }
        //}

        private EntityBase _Tag;
        /// <summary></summary>
        public EntityBase Tag
        {
            get
            {
                return this._Tag;
            }
            set
            {
                this._Tag = value;
            }
        }

        private EntityControlBase _Control;
        /// <summary></summary>
        public EntityControlBase Control
        {
            get
            {
                return this._Control;
            }
            set
            {
                this._Control = value;
            }
        }

        private bool _ConstrainedToConvas;
        /// <summary></summary>
        public bool ConstrainedToConvas
        {
            get
            {
                return this._ConstrainedToConvas;
            }
            set
            {
                this._ConstrainedToConvas = value;
            }
        }

        private bool _Selected = false;
        public bool Selected
        {
            get
            {
                return _Selected;
            }
        }
        /// <summary>
        /// use highlight template when selected
        /// </summary>
        public void SetSelected(bool selected, VerticeVisual vv)
        {
            if(this._Selected !=selected)
            {
                this._Selected = selected;
                if (this.Tag != null)
                {
                    string imgFileName = vv.Icon;
                    if (this._Selected)
                    {
                        imgFileName = vv.SelectedIcon;
                    }
                    string imgFilePath = "/" + EntityIcons.ImageFolder + "/" + imgFileName;
                    BitmapImage img = new BitmapImage();
                    Uri imgUri = new Uri(imgFilePath, UriKind.Relative);
                    img.BeginInit();
                    img.UriSource = imgUri;
                    img.EndInit();
                    this._Control.SwitchableControl(img, this._Selected);
                    this._Control.InvalidateVisual();
                }
            }
        }

        private bool _Disabled = false;
        /// <summary>
        /// use grayed-out template when disabled
        /// </summary>
        public bool Disabled
        {
            get
            {
                return this._Disabled;
            }
        }
        public void SetDisabled(bool disabled, VerticeVisual vv)
        {
            if(this._Disabled !=disabled)
            {
                this._Disabled = disabled;
                this.Control.SetDisabled(this._Disabled);
            }
        }

        private bool _Highlighted = false;
        /// <summary></summary>
        public bool Highlighted
        {
            get
            {
                return this._Highlighted;
            }
            set
            {
                if(this._Highlighted !=value)
                {
                    this._Highlighted = value;
                    this.Control.SetHighlighted(this._Highlighted);
                }
            }
        }
        #endregion

        #region force
        private Vector _Position;
        /// <summary></summary>
        public Vector Position
        {
            get
            {
                return this._Position;
            }
            set
            {
                this._Position = value;
            }
        }

        private Vector _Force;
        /// <summary></summary>
        public Vector Force
        {
            get
            {
                return this._Force;
            }
            set
            {
                this._Force = value;
            }
        }

        private Vector _Velocity;
        /// <summary></summary>
        public Vector Velocity
        {
            get
            {
                return this._Velocity;
            }
            set
            {
                this._Velocity = value;
            }
        }

        private bool _CanMove;
        /// <summary></summary>
        public bool CanMove
        {
            get
            {
                return this._CanMove;
            }
            set
            {
                this._CanMove = value;
            }
        }
        #endregion

        #region measures
        private int _Degree;
        /// <summary></summary>
        public int Degree
        {
            get
            {
                return this._Degree;
            }
            set
            {
                this._Degree = value;
            }
        }

        private int _InDegree;
        /// <summary></summary>
        public int InDegree
        {
            get
            {
                return this._InDegree;
            }
            set
            {
                this._InDegree = value;
            }
        }

        private int _OutDegree;
        /// <summary></summary>
        public int OutDegree
        {
            get
            {
                return this._OutDegree;
            }
            set
            {
                this._OutDegree = value;
            }
        }

        private double _CloseCentrality;
        /// <summary></summary>
        public double CloseCentrality
        {
            get
            {
                return this._CloseCentrality;
            }
            set
            {
                this._CloseCentrality = value;
            }
        }

        private double _BetweenCentrality;
        /// <summary></summary>
        public double BetweenCentrality
        {
            get
            {
                return this._BetweenCentrality;
            }
            set
            {
                this._BetweenCentrality = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public Vertice()
        {
            this._ID = Guid.NewGuid();
            //this._Group = 0;
            //TextBlock tb = new TextBlock();
            //tb.Text = string.Empty;
            //tb.Foreground = new SolidColorBrush(Color.FromArgb(125, 0, 0, 0));
            //tb.Background = new SolidColorBrush(Colors.Transparent);
            //tb.Visibility = Visibility.Collapsed;
            //this._Label = tb;
            this._Position = new Vector();
            this._Force=new Vector();
            this._Velocity=new Vector();
            this._Tag = null;
            this._CanMove = true;

            this._Degree = 0;
            this._InDegree = 0;
            this._OutDegree = 0;
            this._CloseCentrality = 0;
            this._BetweenCentrality = 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public Vertice(Guid id)
            : this()
        {
            this._ID = id;
            //TextBlock tb = new TextBlock();
            //tb.Text = label;
            //tb.Foreground = new SolidColorBrush(Color.FromArgb(125, 0, 0, 0));
            //tb.Background = new SolidColorBrush(Colors.Transparent);
            //tb.Visibility = Visibility.Collapsed;
            //this._Label = tb;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <param name="tag"></param>
        public Vertice(Guid id, EntityBase tag)
            : this(id)
        {
            this._Tag = tag;
            //this._Group = clusterID;
        }
        #endregion

        /// <summary>
        /// make sure control centers around the particle
        /// </summary>
        public void SnapControl()
        {
            if (this._Control != null)
            {
                this._Control.SetValue(Canvas.LeftProperty, this._Position.X - this._Control.ActualWidth / 2.0);
                this._Control.SetValue(Canvas.TopProperty, this._Position.Y - this._Control.ActualHeight / 2.0);
                this._Control.Arrange(new Rect(this._Position.ToPoint(), this._Control.DesiredSize));

                //if (showLabel)
                //{
                //    Point position = new Point(this.Position.X - this.Label.ActualWidth/2,
                //                               this.Position.Y + this.Control.ActualHeight);
                //    this.Label.SetValue(Canvas.LeftProperty, position.X);
                //    this.Label.SetValue(Canvas.TopProperty, position.Y);
                //    this.Label.Arrange(new Rect(position, this.Label.DesiredSize));
                //    this.Label.Visibility = Visibility.Visible;
                //}
                //else
                //    this.Label.Visibility = Visibility.Collapsed;
            }
        }

        public void MoveToPosition(Vector delta)
        {
            if (this.CanMove)
                this._Position += delta;
        }

        public void AddForce(Vector newForce)
        {
            this._Force += newForce;
        }

        public void ResetForce()
        {
            this._Force = new Vector();
        }

        public void SetPosition(Vector position, Rect constraintsRectangle)
        {
            if (this._Control != null)
            {
                position.X = Math.Min(constraintsRectangle.Right, Math.Max(constraintsRectangle.Left, position.X));
                position.Y = Math.Min(constraintsRectangle.Bottom, Math.Max(constraintsRectangle.Top, position.Y));
            }
            this._Position = position;
            
            this.FireMoveEvent();
        }

        private void FireMoveEvent()
        {
            if (this.Move != null)
                this.Move(this);
        }
    }
}
